//*************************************************************************************
// File:     EntityFactory.cs
//*************************************************************************************
// Description: Define la clase abstracta generica de la que derivan las factorias de
//              entidades de la simulacion. Tambien define la clase abstracta de base,
//              BaseFactory que implementa los miembros comunes a todas las instancias
//              de factorias.
//*************************************************************************************
// Classes:      EntityFactory<T> : BaseFactory where T : XGDESKEntity
//*************************************************************************************
// Use:         Las clases derivadas de EntityFactory<T> deberan definir el tipo pasado
//              a la clase generica de base. Se debe sobrecargar el metodo abstracto
//              CreateAs(byte) para llamar al constructor de la entidad. Esta llamada
//              debe contener, entre otros, dos argumentos byte, uno para el tipo de
//              objeto, obtenido de BaseFactory.ObjectType, y el otro el valor resevado
//              para la variante de tipo de instancia, que es el parametro byte que ha
//              sido pasado al llamar la funcion.
//              Es importante notar que los valores 0 y 1 se reservan automaticamente
//              en el constructor, y puede recurrirse a ellos con las llamadas a las
//              funciones CreateAsTemporal() y CreateAsDefault(), respectivamente. El
//              valor 0 representa instancias temporales, y el valor 1 representa un
//              tipo de instancia por defecto.
//*************************************************************************************
// Author:      ManOguaR
//*************************************************************************************

using Xeralabs.Core.Entities.Internal;

namespace Xeralabs.Core.Entities
{
    /// <summary>
    /// Clase generica abstracta para la creacion de entidades basadas en la clase Xeralabs.GDESK.Entities.XGDESKEntity
    /// Como requisito de implementacion, las factorias derivadas deben ser singleton, o garantizar de algun modo
    /// que no seran creadas dos instancias con un mismo parametro de tipo base.
    /// </summary>
    /// <typeparam name="T">Un tipo derivado de <see cref="Xeralabs.Core.Entities.XGDESKEntity"/></typeparam>
    public abstract class EntityFactory<T> : BaseFactory
        where T : XGDESKEntity
    {
        private byte _reservedTemporal;
        private byte _reservedDefault;

        /// <summary>
        /// Constructor protegido. Realiza la reserva del valor para instancias temporales y por defecto (0 y 1 respectivamente).
        /// </summary>
        protected EntityFactory()
            : base()
        {
            _reservedTemporal = GUID64.GetReservedValue(this.ObjectType);
            _reservedDefault = GUID64.GetReservedValue(this.ObjectType);
        }

        /// <summary>
        /// Metodo para reservar un valor en GUID64 (de 2 a 255). La implementacion externa se encarga de la administracion
        /// de dichos valores.
        /// </summary>
        /// <returns>El nuevo valor reservado.</returns>
        protected byte ReserveValue()
        {
            return GUID64.GetReservedValue(this.ObjectType);
        }

        /// <summary>
        /// Metodo para crear una entidad por defecto. Este metodo llama al metodo abstracto CreateAs(byte).
        /// </summary>
        /// <returns>La entidad creada por defecto.</returns>
        protected T CreateAsDefault()
        {
            return this.CreateAs(this._reservedDefault);
        }
        /// <summary>
        /// Metodo para crear una entidad temporal. Este metodo llama al metodo abstracto CreateAs(byte).
        /// </summary>
        /// <returns>La entidad creada de forma temporal.</returns>
        protected T CreateAsTemporal()
        {
            return this.CreateAs(this._reservedTemporal);
        }
        /// <summary>
        /// Metodo abstracto para la creacion de una nueva entidad. Este metodo debe sobrecargarse con una llamada al
        /// constructor de la clase derivada de <see cref="Xeralabs.Core.Entities.XGDESKEntity"/> proporcionada como parametro de la clase
        /// generica de base. La sobrecarga del constructor debe pasar <see cref="BaseFactory.ObjectType"/> y <see cref="reserved"/>.
        /// </summary>
        /// <param name="reserved">El valor reservado o variante de tipo de objeto que se desea instanciar. 0 y 1 quedan reservados para instancias temporales y por defecto, respectivamente.
        /// Los valores reservados entre 2 y 255 quedan disponibles para otras variantes de instancia del mismo tipo de objeto.</param>
        /// <returns>Una nueva instancia de la clase derivada de <see cref="Xeralabs.Core.Entities.XGDESKEntity"/> proporcionada como parametro.</returns>
        protected abstract T CreateAs(byte reserved);

        public virtual void DisposeInactive(ulong entityGUID)
        {
            XGDESKEntity.KillInactiveEntity(entityGUID);
        }
    }
}
